Added `-[NSArray validateAsPropertyList]` and `-[NSDictionary validateAsPropertyList...
[adiumx.git] / Plugins / Purple Service / adiumPurpleDnsRequest.m
bloba3a88f5e8944bb1dcb54abe838f35935fba02c04
1 //
2 //  adiumPurpleDnsRequest.m
3 //  Adium
4 //
5 //  Created by Graham Booker on 2/24/07.
6 //
8 #import "adiumPurpleDnsRequest.h"
10 #include <libpurple/internal.h>
12 #include <sys/socket.h>
13 #include <netdb.h>
15 @interface AdiumPurpleDnsRequest : NSObject {
16         PurpleDnsQueryData *query_data;
17         PurpleDnsQueryResolvedCallback resolved_cb;
18         PurpleDnsQueryFailedCallback failed_cb;
19         BOOL success;
20         int errorNumber;
21         BOOL cancel;
23 + (AdiumPurpleDnsRequest *)lookupRequestForData:(PurpleDnsQueryData *)query_data;
24 - (id)initWithData:(PurpleDnsQueryData *)data resolvedCB:(PurpleDnsQueryResolvedCallback)resolved failedCB:(PurpleDnsQueryFailedCallback)failed;
25 - (void)startLookup:(id)sender;
26 - (void)lookupComplete:(NSValue *)resValue;
27 - (void)cancel;
28 @end
30 @implementation AdiumPurpleDnsRequest
32 static NSMutableDictionary *threads = nil;
34 + (void)initialize
36         [super initialize];
37         
38         threads = [[NSMutableDictionary alloc] init];
41 + (AdiumPurpleDnsRequest *)lookupRequestForData:(PurpleDnsQueryData *)query_data
43         return [threads objectForKey:[NSValue valueWithPointer:query_data]];
46 - (id)initWithData:(PurpleDnsQueryData *)data resolvedCB:(PurpleDnsQueryResolvedCallback)resolved failedCB:(PurpleDnsQueryFailedCallback)failed
48         self = [super init];
49         if(self == nil)
50                 return nil;
51         
52         query_data = data;
53         resolved_cb = resolved;
54         failed_cb = failed;
55         success = FALSE;
56         errorNumber = 0;
57         cancel = FALSE;
58         
59         [threads setObject:self forKey:[NSValue valueWithPointer:query_data]];
60         [self retain];  //Released in lookupComplete:
61         [NSThread detachNewThreadSelector:@selector(startLookup:) toTarget:self withObject:nil];
62         
63         return self;
66 - (void)startLookup:(id)sender
68         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
69         struct addrinfo hints, *res;
70         char servname[20];
71         
72         AILog(@"Performing DNS resolve: %s:%d",purple_dnsquery_get_host(query_data),purple_dnsquery_get_port(query_data));
73         g_snprintf(servname, sizeof(servname), "%d", purple_dnsquery_get_port(query_data));
74         memset(&hints, 0, sizeof(hints));
75         
76         /* This is only used to convert a service
77          * name to a port number. As we know we are
78          * passing a number already, we know this
79          * value will not be really used by the C
80          * library.
81          */
82         hints.ai_socktype = SOCK_STREAM;
83         errorNumber = getaddrinfo(purple_dnsquery_get_host(query_data), servname, &hints, &res);
84         if (errorNumber == 0) {
85                 success = TRUE;
86         } else {
87                 /*
88                  if (show_debug)
89                         printf("dns[%d] Error: getaddrinfo returned %d\n", getpid(), rc);
90                  dns_params.hostname[0] = '\0';
91                  */
92                 success = FALSE;
93         }
94         
95         [self performSelectorOnMainThread:@selector(lookupComplete:) withObject:(success ? [NSValue valueWithPointer:res] : nil) waitUntilDone:NO];
96         [pool release];
99 - (void)lookupComplete:(NSValue *)resValue
101         if (cancel) {
102                 //Cancelled, so take no action now that the lookup is complete.
104         } else if (success && resValue) {
105                 //Success! Build a list of our results and pass it to the resolved callback
106                 AILog(@"DNS resolve complete for %s:%d",purple_dnsquery_get_host(query_data),purple_dnsquery_get_port(query_data));
107                 struct addrinfo *res, *tmp;
108                 GSList *returnData = NULL;
110                 res = [resValue pointerValue];
111                 tmp = res;
112                 while (res) {
113                         size_t addrlen = res->ai_addrlen;
114                         struct sockaddr *addr = g_malloc(addrlen);
115                         memcpy(addr, res->ai_addr, addrlen);
116                         returnData = g_slist_append(returnData, GINT_TO_POINTER(addrlen));
117                         returnData = g_slist_append(returnData, addr);
118                         res = res->ai_next;
119                 }
120                 freeaddrinfo(tmp);
121                 
122                 resolved_cb(query_data, returnData);
124         } else {
125                 //Failure :( Send an error message to the failed callback
126                 char message[1024];
127                 
128                 g_snprintf(message, sizeof(message), _("Error resolving %s:\n%s"),
129                                    purple_dnsquery_get_host(query_data), gai_strerror(errorNumber));
130                 failed_cb(query_data, message);
131         }
133         //Release our retain in init...
134         [self autorelease];
136         if (query_data) {
137                 //Can happen if we were cancelled
138                 [threads removeObjectForKey:[NSValue valueWithPointer:query_data]];
139         }
142 - (void)cancel
144         //Can't stop an existing thread, so let it just die gracefully when it is done
145         cancel = TRUE;
146         
147         //To avoid collisions and the like
148         [threads removeObjectForKey:[NSValue valueWithPointer:query_data]];
149         query_data = NULL;
152 @end
154 gboolean adiumPurpleDnsRequestResolve(PurpleDnsQueryData *query_data, PurpleDnsQueryResolvedCallback resolved_cb, PurpleDnsQueryFailedCallback failed_cb)
156         [[[AdiumPurpleDnsRequest alloc] initWithData:query_data resolvedCB:resolved_cb failedCB:failed_cb] autorelease];
157         return TRUE;
160 void adiumPurpleDnsRequestDestroy(PurpleDnsQueryData *query_data)
162         [[AdiumPurpleDnsRequest lookupRequestForData:query_data] cancel];
165 static PurpleDnsQueryUiOps adiumPurpleDnsRequestOps = {
166         adiumPurpleDnsRequestResolve,
167         adiumPurpleDnsRequestDestroy
170 PurpleDnsQueryUiOps *adium_purple_dns_request_get_ui_ops(void)
172         return &adiumPurpleDnsRequestOps;